package gugga.tasks
{
	import flash.events.EventDispatcher;
	
	import gugga.tasks.events.TaskEvent;
	import gugga.eventHelpers.EventRethrower;
	import gugga.debug.Assertion;
	
	[Event(name="start", type="TaskEvent")]
	[Event(name="interrupted", type="TaskEvent")]
	[Event(name="completed", type="TaskEvent")]
	
	/**
	 * The <code>WrappingTask</code> is usefull in cases when we need to initialize a task container with a task
	 * which is still not initialized and maybe it's even undefined at this point. Instead of the actual task you 
	 * can add a <code>WrappingTask</code> to that task container, and later when possible you will initialize the 
	 * actual task, and wrap it in the <code>WrappingTask</code>, through the <code>WrappedTask</code>-setter 
	 * property.
	 * <p> 
	 * The <code>WrappingTask</code> will transparently rethrow the <b><i>start</i></b>, <b><i>interrupted</i></b> 
	 * and <b><i>completed</i></b>-events dispatched from the wrapped task.
	 * <p>
	 * If you want also to rethrow <b><i>progress</i></b>-events, you should use an <code>IProgressiveTask</code> 
	 * and a <code>WrappingProgressiveTask</code> instead of <code>WrappingTask</code>.
	 * 
	 * @see gugga.tasks.WrappingProgressiveTask
	 */	
	public class WrappingTask extends EventDispatcher implements ITask 
	{
		protected var mWrappedTask : ITask;
		
		public function get WrappedTask() : ITask { return mWrappedTask; }
		public virtual function set WrappedTask(aValue:ITask) : void 
		{ 
			mWrappedTask = aValue;
			stopRethrowers();
			startRethrowers();
		}	
		
		private var mCompletedRethrower : EventRethrower;
		private var mInterruptedRethrower : EventRethrower;
		private var mStartRethrower : EventRethrower;	
		
		public function WrappingTask(aWrappedTask:ITask) 
		{
			super();
			WrappedTask = aWrappedTask;
		}
			
		public function start() : void 
		{
			Assertion.warningIfNull(mWrappedTask, "WrappedTask not set", this, arguments);
			
			mWrappedTask.start();
		}
	
		public function isRunning() : Boolean 
		{
			return mWrappedTask.isRunning();
		}
	
		public function isImmediatelyInterruptable() : Boolean 
		{
			return mWrappedTask.isImmediatelyInterruptable();
		}
	
		public function interrupt() : void 
		{
			mWrappedTask.interrupt();	
		}
		
		private function stopRethrowers() : void
		{
			if (mCompletedRethrower)
			{
				mCompletedRethrower.stopListening();
			}
			
			if (mInterruptedRethrower)
			{
				mInterruptedRethrower.stopListening();
			}
			
			if (mStartRethrower)
			{
				mStartRethrower.stopListening();	 
			}
		}
		
		private function startRethrowers() : void 
		{
			if (mWrappedTask)
			{
				mCompletedRethrower = EventRethrower.create(this, mWrappedTask, TaskEvent.COMPLETED);
				mInterruptedRethrower = EventRethrower.create(this, mWrappedTask, TaskEvent.INTERRUPTED);
				mStartRethrower = EventRethrower.create(this, mWrappedTask, TaskEvent.START);
			}
		}
	}
}